/**
  ******************************************************************************
  * File Name          : exio.c
  * Description        : 
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "route_expio_485.h"
#include <string.h>

typedef enum
{
  RS485_RCVST_DEV_ADDR = 0,
	RS485_RCVST_DEV_TYPE,
	RS485_RCVST_TRANS_DIR,
	RS485_RCVST_PL_TYPE,
	RS485_RCVST_PL_LEN_H,
  RS485_RCVST_PL_LEN_L,
	RS485_RCVST_CRC_H,
  RS485_RCVST_CRC_L,
  RS485_RCVST_PAYLOAD,
}RS485_RecvStateType;

extern void RS485_Sendbuf(const uint8_t *buf, uint32_t len);

uint8_t RS485_LocalAddr = RS485_LOCAL_ADDRESS;

/* 中断接收状态控制 */
volatile RS485_RecvStateType rs485_isr_recvstate = RS485_RCVST_DEV_ADDR;

void RS485_GetLocalAddress(void)
{
  uint8_t sw_read = 0;
	
	if(SW1() == 0)
	{
		sw_read |= 0x20;
	}
	
	if(SW2() == 0)
	{
		sw_read |= 0x10;
	}
	
	if(SW3() == 0)
	{
		sw_read |= 0x08;
	}
	
	if(SW4() == 0)
	{
		sw_read |= 0x04;
	}
	
	if(SW5() == 0)
	{
		sw_read |= 0x02;
	}
	
	if(SW6() == 0)
	{
		sw_read |= 0x01;
	}

  RS485_LocalAddr = (sw_read | ROUTE_DEVADDR_MASK);
}

uint8_t RS485_LinkSend(Route_PayloadType *rtpl)
{
  rtpl->dev_addr = RS485_LocalAddr;
  rtpl->dev_type = Route_LocalDevType;
  
	Route_PayloadCRC(rtpl, ROUTE_PLCRC_WRITE);
  
	RS485_Sendbuf((uint8_t *)rtpl, rtpl->pl_len+8);
  
  return 0;
}

void RS485_BreakIsr(void)
{
	rs485_isr_recvstate = RS485_RCVST_DEV_ADDR;
}

void RS485_RecvIsr(uint8_t dat)
{
	static uint8_t count = 0;
	
	switch(rs485_isr_recvstate)
	{
		case RS485_RCVST_DEV_ADDR:
			if((dat == RS485_LocalAddr) || (dat == 0xFEu))
			{
				Route_485_rx_link_isr.dev_addr = dat;
				rs485_isr_recvstate = RS485_RCVST_DEV_TYPE;
			}
			break;

		case RS485_RCVST_DEV_TYPE:
			if((dat == Route_LocalDevType) || (dat == RT_DV_UN))
			{
				Route_485_rx_link_isr.dev_type = dat;
				rs485_isr_recvstate = RS485_RCVST_TRANS_DIR;
			}
      else
      {
        rs485_isr_recvstate = RS485_RCVST_DEV_ADDR;
      }
			break;
		
		case RS485_RCVST_TRANS_DIR:
			if((dat == ROUTE_TRSDIR_NET_TO_SUBDEV) || (dat == ROUTE_TRSDIR_LOCAL_TO_SUBDEV))
			{
				Route_485_rx_link_isr.trans_dir = dat;
				rs485_isr_recvstate = RS485_RCVST_PL_TYPE;
			}
			else
			{
				rs485_isr_recvstate = RS485_RCVST_DEV_ADDR;
			}
			break;
		
    case RS485_RCVST_PL_TYPE:
      Route_485_rx_link_isr.pl_type = dat;
      rs485_isr_recvstate = RS485_RCVST_PL_LEN_H;
      break;
    
    case RS485_RCVST_PL_LEN_H:
      Route_485_rx_link_isr.pl_len = (((uint16_t)dat) & 0x00FFu);
      rs485_isr_recvstate = RS485_RCVST_PL_LEN_L;
      break;
    
    case RS485_RCVST_PL_LEN_L:
      Route_485_rx_link_isr.pl_len += ((((uint16_t)dat) << 8) & 0xFF00u);
      if(Route_485_rx_link_isr.pl_len < ROUTE_PAYLOAD_MAXLEN)
      {
        rs485_isr_recvstate = RS485_RCVST_CRC_H;
      }
      else
      {
        rs485_isr_recvstate = RS485_RCVST_DEV_ADDR;
      }
      break;
    
    case RS485_RCVST_CRC_H:
			Route_485_rx_link_isr.crc16 = (((uint16_t)dat) & 0x00FFu);
			rs485_isr_recvstate = RS485_RCVST_CRC_L;
			break;
    
    case RS485_RCVST_CRC_L:
			Route_485_rx_link_isr.crc16 += ((((uint16_t)dat) << 8) & 0xFF00u);
      if(Route_485_rx_link_isr.pl_len == 0)
      {
        if(Route_485RxLink_Qhd != NULL)
        {
          xQueueSendFromISR(Route_485RxLink_Qhd, &Route_485_rx_link_isr, NULL);
        }
        rs485_isr_recvstate = RS485_RCVST_DEV_ADDR;
      }
      else
      {
        count = 0;
        rs485_isr_recvstate = RS485_RCVST_PAYLOAD;
      }
			break;
    
		case RS485_RCVST_PAYLOAD:
			Route_485_rx_link_isr.payload[count++] = dat;
			if(count >= Route_485_rx_link_isr.pl_len)
			{
        if(Route_485RxLink_Qhd != NULL)
        {
          xQueueSendFromISR(Route_485RxLink_Qhd, &Route_485_rx_link_isr, NULL);
        }
				rs485_isr_recvstate = RS485_RCVST_DEV_ADDR;
			}
			break;
			
		default:
			rs485_isr_recvstate = RS485_RCVST_DEV_ADDR;
			break;
	}
}
